/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.method;

import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.entity.changeset.ValueObjModifyChangeDetail;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.AccessorClassGenContext;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class NestedAccessorAcceptChangeGen extends AccessorAcceptChangeGen
{
	private static String ParamVar = "var";
	private static String ParamPropertyChange = "propertyChange";

	@Deprecated
	public NestedAccessorAcceptChangeGen(IGspCommonDataType dataType,
			AccessorClassGenContext parentContext) {
		super(parentContext, dataType.getCode(),
				dataType.getContainElements().stream().map(item -> new MediatePropertyInfo(item)).collect(
						Collectors.toList()));
	}

	public NestedAccessorAcceptChangeGen(String nodeCode,List<MediatePropertyInfo> dataType, AccessorClassGenContext parentContext) {
		super(parentContext, nodeCode, dataType);
	}

	@Override
	protected Block buildMethodBody() {
		Block block=ast.newBlock();
		addSuperStatement(block);
		addNewModifyChangeStatement(block);
		addJugeModifyNullStatement(block);
		addSetChangePropValuesStatement(block);
		return block;
	}

	private void addNewModifyChangeStatement(Block block) {
		Object value = null;
		String change = value instanceof String ? (String) value : null;
		VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
		variableDeclarationFragment.setName(ast.newSimpleName(ParamVar));
		variableDeclarationFragment.setInitializer(ExpressionUtils
				.getAsExpression(ast, ast -> ast.newSimpleName(FormalParName),
						ast -> new TypeInfo(ValueObjModifyChangeDetail.class).getType(ast)));
		addImport(ValueObjModifyChangeDetail.class.getTypeName());

		VariableDeclarationStatement variableDeclarationStatement = ast
				.newVariableDeclarationStatement(variableDeclarationFragment);
		variableDeclarationStatement.setType(
				new com.inspur.edp.caf.generator.baseInfo.TypeInfo(ValueObjModifyChangeDetail.class).getType(ast));

		block.statements().add(variableDeclarationStatement);
	}

	private void addJugeModifyNullStatement(Block block) {
		IfStatement ifStatement = ast.newIfStatement();

		InfixExpression infixExpression = ast.newInfixExpression();
		infixExpression.setOperator(InfixExpression.Operator.EQUALS);
		infixExpression.setLeftOperand(ast.newSimpleName(ParamVar));
		infixExpression.setRightOperand(ast.newNullLiteral());

		ifStatement.setExpression(infixExpression);
		addImport(CefException.class.getTypeName());
		Block blockStatement = ast.newBlock();
		ThrowStatement throwStatement = GeneratorUtil.getThrowStatement(ast,null);
//		SetExceptionCode setExceptionCode =new SetExceptionCode();
//		ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
//		setExceptionCode.setClassInstanceCreation(classInstanceCreation,ast,"","");
//		classInstanceCreation.setType(
//				new com.inspur.edp.caf.generator.baseInfo.TypeInfo(RuntimeException.class).getType(ast));
		blockStatement.statements().add(throwStatement);

		ifStatement.setThenStatement(blockStatement);

		block.statements().add(ifStatement);
	}

	private void addSetChangePropValuesStatement(Block block) {
		EnhancedForStatement forStatement = ast.newEnhancedForStatement();
		addSetChangeProForParameter(forStatement);
		addSetChangeProForExpression(forStatement);
		addSetChangeProForBody(forStatement);
		block.statements().add(forStatement);
	}

	private void addSetChangeProForParameter(EnhancedForStatement forStatement) {
		SingleVariableDeclaration singleVariableDeclaration = ast.newSingleVariableDeclaration();
		singleVariableDeclaration.setName(ast.newSimpleName(ParamPropertyChange));
		ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(
				ast.newQualifiedName(ast.newName(Map.class.getTypeName()), ast.newSimpleName("Entry"))));
		parameterizedType.typeArguments()
				.add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(String.class).getType(ast));
		parameterizedType.typeArguments()
				.add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(Object.class).getType(ast));
		singleVariableDeclaration.setType(parameterizedType);

		forStatement.setParameter(singleVariableDeclaration);
	}


	private void addSetChangeProForExpression(EnhancedForStatement forStatement) {
		MethodInvocation methodInvocation = ast.newMethodInvocation();
		methodInvocation.setName(ast.newSimpleName("entrySet"));

		MethodInvocation methodInvocation1 = ast.newMethodInvocation();
		methodInvocation1.setName(ast.newSimpleName("getPropertyChanges"));
		methodInvocation1.setExpression(ast.newSimpleName(ParamVar));
		methodInvocation.setExpression(methodInvocation1);

		forStatement.setExpression(methodInvocation);
	}

	private void addSetChangeProForBody(EnhancedForStatement forStatement) {
		Block block = ast.newBlock();
		SwitchStatement switchStatement = ast.newSwitchStatement();
		addSetChangeProForSwitchExpression(switchStatement);
		addSetChangeProCases(switchStatement);
		block.statements().add(switchStatement);
		forStatement.setBody(block);
	}
	private void addSetChangeProForSwitchExpression(SwitchStatement switchStatement) {
		MethodInvocation methodInvocation = ast.newMethodInvocation();
		methodInvocation.setExpression(ast.newSimpleName(ParamPropertyChange));
		methodInvocation.setName(ast.newSimpleName("getKey"));
		switchStatement.setExpression(methodInvocation);
	}

	private void addSetChangeProCases(SwitchStatement switchStatement) {
		for (MediatePropertyInfo info : dataType) {
			if(info.getElement() != null) {
				if(!info.getExtendInfos().containsKey("AssoUdtAtrribute")) {
					addSetChangeProCase(ast, nodeCode, info, switchStatement, parentContext);
				}
			}
		}
	}
}
